package com.cloudlead.plugin.security.service.impl;

import com.cloudlead.common.lang.annotation.Label;
import com.cloudlead.common.lang.security.Principal;
import com.cloudlead.common.persistence.QueryDslRepository;
import com.cloudlead.common.persistence.impl.AbstractMultiTableCrudService;
import com.cloudlead.plugin.security.BusinessModules;
import com.cloudlead.plugin.security.entity.EScUser;
import com.cloudlead.plugin.security.query.*;
import com.cloudlead.plugin.security.repository.EScUserRepository;
import com.cloudlead.plugin.security.service.ScUserService;
import com.cloudlead.plugin.security.service.UserInfoService;
import com.cloudlead.plugin.security.vo.ScUser;
import com.mysema.query.BooleanBuilder;
import com.mysema.query.sql.SQLQuery;
import com.mysema.query.sql.SQLSubQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * ScUserServiceImpl is a Codegen service implement type
 */
@Service("scUserService")
@Label("用户服务实现")
public class ScUserServiceImpl extends AbstractMultiTableCrudService<EScUserRepository, ScUser, EScUser> implements ScUserService, UserInfoService {

    @Autowired
    public ScUserServiceImpl(EScUserRepository repository) {
        super(BusinessModules.ScUser, repository);
        this.hasCache = true;
    }

    @Override
    public List<String> findPrivileges(final String username, String group) {
        return repository.find(new QueryDslRepository.Query() {
            @Override
            public List<String> queryInTransactional(SQLQuery sqlQuery) {
                BooleanBuilder booleanBuilder = new BooleanBuilder();
                if (StringUtils.isNotBlank(group)) {
                    booleanBuilder.and(QScGroup.scGroup.name.eq(group));
                }
                List<String> list = sqlQuery
                        .leftJoin(QScUserHasRole.scUserHasRole)
                        .on(QScUserHasRole.scUserHasRole.scUserId.eq(QScUser.scUser.id))
                        .leftJoin(QScUserHasPrivilege.scUserHasPrivilege)
                        .on(QScUserHasPrivilege.scUserHasPrivilege.scUserId.eq(QScUser.scUser.id))
                        .leftJoin(QScGroupHasUser.scGroupHasUser)
                        .on(QScGroupHasUser.scGroupHasUser.scUserId.eq(QScUser.scUser.id))
                        .leftJoin(QScGroup.scGroup)
                        .on(QScGroup.scGroup.available.eq(true).and(QScGroup.scGroup.id.eq(QScGroupHasUser.scGroupHasUser.scGroupId)))
                        .leftJoin(QScGroupHasRole.scGroupHasRole)
                        .on(QScGroup.scGroup.id.eq(QScGroupHasRole.scGroupHasRole.scGroupId))
                        .leftJoin(QScGroupHasPrivilege.scGroupHasPrivilege).on(QScGroup.scGroup.id.eq(QScGroupHasPrivilege.scGroupHasPrivilege.scGroupId))
                        .leftJoin(QScRole.scRole)
                        .on(QScRole.scRole.available.eq(true).and(QScRole.scRole.id.eq(QScUserHasRole.scUserHasRole.scRoleId).or(QScRole.scRole.id.eq(QScGroupHasRole.scGroupHasRole.scRoleId))))
                        .leftJoin(QScRoleHasPrivilege.scRoleHasPrivilege)
                        .on(QScRole.scRole.id.eq(QScRoleHasPrivilege.scRoleHasPrivilege.scRoleId))
                        .leftJoin(QScPrivilege.scPrivilege)
                        .on(QScPrivilege.scPrivilege.available.eq(true).and(QScPrivilege.scPrivilege.id.eq(QScRoleHasPrivilege.scRoleHasPrivilege.scPrivilegeId)
                                .or(QScPrivilege.scPrivilege.id.eq(QScGroupHasPrivilege.scGroupHasPrivilege.scPrivilegeId))
                                .or(QScPrivilege.scPrivilege.id.eq(QScUserHasPrivilege.scUserHasPrivilege.scPrivilegeId))))
                        .where(QScUser.scUser.username.eq(username).and(booleanBuilder.getValue())
                                .and(QScPrivilege.scPrivilege.id.notIn(new SQLSubQuery().from(QScGroupHasPrivilege.scGroupHasPrivilege).where(QScGroupHasPrivilege.scGroupHasPrivilege.isPermission.eq(false)).list(QScGroupHasPrivilege.scGroupHasPrivilege.scPrivilegeId)))
                                .and(QScPrivilege.scPrivilege.id.notIn(new SQLSubQuery().from(QScUserHasPrivilege.scUserHasPrivilege).where(QScUserHasPrivilege.scUserHasPrivilege.isPermission.eq(false)).list(QScUserHasPrivilege.scUserHasPrivilege.scPrivilegeId)))
                                .and(QScGroupHasPrivilege.scGroupHasPrivilege.isPermission.isNull().or(QScGroupHasPrivilege.scGroupHasPrivilege.isPermission.eq(true))))
                        .distinct().list(QScPrivilege.scPrivilege.name);
                return list;
            }
        });
    }

    @Override
    public List<String> findRoles(final String username, String group) {
        return repository.find(new QueryDslRepository.Query() {
            @Override
            public List<String> queryInTransactional(SQLQuery sqlQuery) {
                BooleanBuilder booleanBuilder = new BooleanBuilder();
                booleanBuilder.and(QScUser.scUser.username.eq(username));
                if (StringUtils.isNotBlank(group)) {
                    booleanBuilder.and(QScGroup.scGroup.name.eq(group));
                }
                List<String> list = sqlQuery
                        .leftJoin(QScUserHasRole.scUserHasRole)
                        .on(QScUserHasRole.scUserHasRole.scUserId.eq(QScUser.scUser.id))
                        .leftJoin(QScGroupHasUser.scGroupHasUser)
                        .on(QScGroupHasUser.scGroupHasUser.scUserId.eq(QScUser.scUser.id))
                        .leftJoin(QScGroup.scGroup)
                        .on(QScGroup.scGroup.available.eq(true).and(QScGroup.scGroup.id.eq(QScGroupHasUser.scGroupHasUser.scGroupId)))
                        .leftJoin(QScGroupHasRole.scGroupHasRole)
                        .on(QScGroup.scGroup.id.eq(QScGroupHasRole.scGroupHasRole.scGroupId))
                        .leftJoin(QScRole.scRole)
                        .on(QScRole.scRole.available.eq(true).and(QScRole.scRole.id.eq(QScUserHasRole.scUserHasRole.scRoleId).or(QScRole.scRole.id.eq(QScGroupHasRole.scGroupHasRole.scRoleId))))
                        .where(booleanBuilder.getValue()).distinct().list(QScRole.scRole.name);
                return list;
            }
        });
    }

    @Override
    public List<String> findGroups(final String username) {
        return repository.find(new QueryDslRepository.Query() {
            @Override
            public List<String> queryInTransactional(SQLQuery sqlQuery) {
                List<String> list = sqlQuery.leftJoin(QScGroupHasUser.scGroupHasUser).on(QScGroupHasUser.scGroupHasUser.scUserId.eq(QScUser.scUser.id)).leftJoin(QScGroup.scGroup)
                        .on(QScGroup.scGroup.available.eq(true).and(QScGroup.scGroup.id.eq(QScGroupHasUser.scGroupHasUser.scGroupId)))
                        .where(QScUser.scUser.username.eq(username)).distinct().list(QScGroup.scGroup.name);
                return list;
            }
        });
    }

    @Override
    public Principal findByUsername(String username) {
        ScUser example = new ScUser();
        example.setUsername(username);
        ScUser scUser = this.findOne(example);
        if (null == scUser) {
            return null;
        }
        Principal principal = new Principal();
        principal.setUsername(scUser.getUsername());
        principal.setMobile(scUser.getMobile());
        principal.setEmail(scUser.getEmail());
        return principal;
    }

    @Override
    public Principal findByMobile(String mobile) {
        ScUser example = new ScUser();
        example.setMobile(mobile);
        ScUser scUser = this.findOne(example);
        if (null == scUser) {
            return null;
        }
        Principal principal = new Principal();
        principal.setUsername(scUser.getUsername());
        principal.setMobile(scUser.getMobile());
        principal.setEmail(scUser.getEmail());
        return principal;
    }


    @Override
    public Principal findByEmail(String email) {
        ScUser example = new ScUser();
        example.setEmail(email);
        ScUser scUser = this.findOne(example);
        if (null == scUser) {
            return null;
        }
        Principal principal = new Principal();
        principal.setUsername(scUser.getUsername());
        principal.setMobile(scUser.getMobile());
        principal.setEmail(scUser.getEmail());
        return principal;
    }
}
